package com.example.transaction.service;

import com.example.transaction.model.Account;
import com.example.transaction.model.TransactionRecord;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

/**
 * 这个服务类用于演示不同的事务嵌套场景
 * 通过设置spring.profiles.active=demo来启用此演示
 */
@Service
@RequiredArgsConstructor
@Slf4j
@Profile("demo")
public class TransactionDemoService implements CommandLineRunner {

    private final AccountService accountService;
    private final TransactionRecordService transactionRecordService;

    @Override
    public void run(String... args) {
        log.info("Starting transaction demo...");
        
        // 打印初始账户状态
        printAllAccounts("Initial state");
        
        // 演示1: 简单转账 - 成功场景
        demoSimpleTransfer();
        
        // 演示2: 简单转账 - 失败场景（余额不足）
        demoInsufficientFundsTransfer();
        
        // 演示3: 批量转账 - 部分成功场景（使用REQUIRES_NEW）
        demoBatchTransferWithPartialSuccess();
        
        // 打印所有交易记录
        printAllTransactions();
    }
    
    private void demoSimpleTransfer() {
        log.info("\n=== Demo 1: Simple Transfer (Success) ===");
        try {
            accountService.transfer("ACC001", "ACC002", new BigDecimal("100"));
            log.info("Transfer successful");
            printAllAccounts("After successful transfer");
        } catch (Exception e) {
            log.error("Transfer failed: {}", e.getMessage());
        }
    }
    
    private void demoInsufficientFundsTransfer() {
        log.info("\n=== Demo 2: Transfer with Insufficient Funds (Failure) ===");
        try {
            // 尝试转账超过账户余额的金额
            accountService.transfer("ACC001", "ACC002", new BigDecimal("10000"));
            log.info("Transfer successful (unexpected)");
        } catch (Exception e) {
            log.error("Transfer failed as expected: {}", e.getMessage());
            printAllAccounts("After failed transfer (balances should be unchanged)");
        }
    }
    
    private void demoBatchTransferWithPartialSuccess() {
        log.info("\n=== Demo 3: Batch Transfer with Partial Success (REQUIRES_NEW) ===");
        
        List<AccountService.TransferRequest> transfers = Arrays.asList(
            // 有效转账
            new AccountService.TransferRequest("ACC002", "ACC003", new BigDecimal("50")),
            // 无效转账 - 余额不足
            new AccountService.TransferRequest("ACC003", "ACC004", new BigDecimal("10000")),
            // 有效转账
            new AccountService.TransferRequest("ACC004", "ACC001", new BigDecimal("200"))
        );
        
        try {
            accountService.batchTransfer(transfers);
            log.info("Batch transfer completed with partial success");
            printAllAccounts("After batch transfer with partial success");
        } catch (Exception e) {
            log.error("Batch transfer failed completely: {}", e.getMessage());
            printAllAccounts("After batch transfer failure");
        }
    }
    
    private void printAllAccounts(String message) {
        log.info("\n--- {} ---", message);
        List<Account> accounts = accountService.getAllAccounts();
        accounts.forEach(account -> 
            log.info("Account: {}, Owner: {}, Balance: {}", 
                    account.getAccountNumber(), 
                    account.getOwnerName(), 
                    account.getBalance())
        );
    }
    
    private void printAllTransactions() {
        log.info("\n--- All Transaction Records ---");
        List<TransactionRecord> records = transactionRecordService.getAllTransactionRecords();
        records.forEach(record -> 
            log.info("Transaction: {}, From: {}, To: {}, Amount: {}, Status: {}", 
                    record.getTransactionId(),
                    record.getFromAccount(),
                    record.getToAccount(),
                    record.getAmount(),
                    record.getStatus())
        );
    }
}